#ifndef EXCEPTION_HPP__
#define EXCEPTION_HPP__

/**
 * \file exception.hpp
 * \author Mason Smith <masonium@caltech.edu>
 * Contains simple runtime error types
 */

#include <stdexcept>
#include <string>

using std::runtime_error;
using std::string;


#define DEFINE_EXTENDED_RUNTIME_ERROR(error_name, parent) \
  class error_name : public parent                 \
  {                                                \
  public:                                          \
    error_name(const string& s) : parent(s) { }    \
  }

//! macro defining a simple error that inherits from the STL runtime_error
#define DEFINE_SIMPLE_RUNTIME_ERROR(error_name)                 \
  DEFINE_EXTENDED_RUNTIME_ERROR(error_name, runtime_error)

DEFINE_SIMPLE_RUNTIME_ERROR(type_error);

DEFINE_SIMPLE_RUNTIME_ERROR(null_pointer_error);
DEFINE_SIMPLE_RUNTIME_ERROR(empty_list_error);
DEFINE_SIMPLE_RUNTIME_ERROR(undefined_function_error);
DEFINE_SIMPLE_RUNTIME_ERROR(null_value_error);

DEFINE_SIMPLE_RUNTIME_ERROR(timeout_error);

// parsing
DEFINE_SIMPLE_RUNTIME_ERROR(parse_error);
DEFINE_EXTENDED_RUNTIME_ERROR(instruction_parse_error, parse_error);
DEFINE_EXTENDED_RUNTIME_ERROR(file_parse_error, parse_error);

// assertion
DEFINE_SIMPLE_RUNTIME_ERROR(assert_test_error);
DEFINE_EXTENDED_RUNTIME_ERROR(acc_equals_error, assert_test_error);

/** signals an error for incorrect argument
 * counts for calling vm functions.
 */
class argument_count_error : public runtime_error
{
public:
  argument_count_error(int _given, int _expected) : 
    runtime_error(""), given(_given), expected(_expected) { }

  int get_num_expected_arguments() const { return expected; }
  int get_num_given_arguments() const { return given; }
  
private:
  int given;
  int expected;
};

#endif
